fix(security): require signed tenant claims on admin endpoints - #268
fix(security): require signed tenant claims on admin endpoints#268seonghobae wants to merge 54 commits into
Conversation
📝 WalkthroughWalkthroughChanges테넌트 관리자 보안
Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related issues
Possibly related PRs
Sequence Diagram(s)sequenceDiagram
participant AdminClient
participant AdminController
participant TenantAccessService
participant DefaultDocumentConversionService
participant InMemoryConversionJobRepository
participant ConversionJobStateStore
participant AdministrativeAuditLogger
AdminClient->>AdminController: signed tenant claims and admin permission
AdminController->>TenantAccessService: requireSigned
TenantAccessService-->>AdminController: TenantContext
AdminController->>DefaultDocumentConversionService: tenant-scoped operation
DefaultDocumentConversionService->>InMemoryConversionJobRepository: tenant and job identifier
InMemoryConversionJobRepository-->>DefaultDocumentConversionService: scoped result
DefaultDocumentConversionService->>ConversionJobStateStore: tenant-bound retry transition
ConversionJobStateStore-->>DefaultDocumentConversionService: retry outcome
AdminController->>AdministrativeAuditLogger: action, outcome, HTTP status
AdminController-->>AdminClient: scoped HTTP response
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Comment |
|
@opencode-agent Rebuild this stacked PR cleanly on authoritative parent #270 exact head Preserve only the bounded administrative-authorization slice represented by the current 31-file diff: signed-claim verification, least-privilege Use a clean parent-based branch history or replace the current branch only after the complete tree is ready. Run the strongest available local |
|
@opencode-agent @cwl-noema-review Review exact stacked head Manual review found that both Keep Draft. Parent #270 must integrate first; then this branch must be reconciled onto protected |
|
@opencode-agent Parent update: rebuild the tenant-scoped administrative authorization slice directly on #270 exact head |
|
@opencode-agent @cwl-noema-review Rebuild this draft as a clean descendant of authoritative parent #270 exact head Fresh GitHub comparison shows current head Reconcile shared Implement test-first, run the strongest available |
|
@opencode-agent Reconstruct this draft as a clean descendant of authoritative parent exact head Required bounded operation:
Do not merge, retarget to |
808e57d to
3796fac
Compare
|
@coderabbitai review @opencode-agent @cwl-noema-review Please independently review exact current head This draft is now a clean descendant of parent #270 exact The exact head has successful fuzz run Submit actionable path-specific findings or a formal exact-head review after your own inspection. Parent integration and a counted independent write-authorized approval remain separate mandatory gates. |
|
I will treat predecessor-head results as stale. I will treat absent CI, Security Scan, and SAST results as not passing.
|
|
@coderabbitai review @opencode-agent @cwl-noema-review Independently review exact current head Verify fail-closed signed-claim construction and freshness/signature/permission checks; The branch currently has successful exact-head fuzz run |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
head='fe2e53328a0b44c1c449d724314c6c4944eb572b'
parent='26563218ae42eaa876c784fcf56b27f8cb810080'
printf '%s\n' '== Current commit and parent relationship =='
git show -s --format='HEAD %H%nParents %P%nSubject %s' "$head"
printf 'merge-base '
git merge-base "$head" "$parent"
printf 'ahead/behind '
git rev-list --left-right --count "$parent...$head"
printf '%s\n' '== Parent-relative changed paths =='
git diff --name-status "$parent" "$head"
printf '%s\n' '== Changed-file structural outline =='
git diff --name-only "$parent" "$head" | while IFS= read -r path; do
case "$path" in
*.java)
printf '\n--- %s ---\n' "$path"
ast-grep outline "$path" --items all --view compact 2>/dev/null || true
;;
esac
done
printf '%s\n' '== Security boundary symbols in changed files =='
git diff --name-only "$parent" "$head" | while IFS= read -r path; do
case "$path" in
*.java|*.yml|*.yaml|*.properties|*.md|*.json)
rg -n -i -C 2 \
'findAllByTenantId|findByTenantAnd(Id|ContentHash)|deleteByTenantAndId|retryDeadLetteredForTenant|TenantContext|admin:(read|write)|AuditPseudonymizer|HMAC|secret|X-Clearfolio|content.?hash' \
"$path" || true
;;
esac
doneLength of output: 89305 🏁 Script executed: #!/bin/bash
set -euo pipefail
print_range() {
local path="$1" start="$2" end="$3"
printf '\n===== %s, lines %s-%s =====\n' "$path" "$start" "$end"
sed -n "${start},${end}p" "$path" | nl -ba -v "$start"
}
print_range src/main/java/com/clearfolio/viewer/auth/TenantAccessService.java 65 190
print_range src/main/java/com/clearfolio/viewer/controller/AdminController.java 45 285
print_range src/main/java/com/clearfolio/viewer/audit/AdministrativeAuditLogger.java 1 230
print_range src/main/java/com/clearfolio/viewer/repository/ConversionJobRepository.java 1 175
print_range src/main/java/com/clearfolio/viewer/repository/ConversionJobStateStore.java 1 135
print_range src/main/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepository.java 1 385
print_range src/main/java/com/clearfolio/viewer/service/DefaultDocumentConversionService.java 210 335
print_range docs/deployment/clearfolio-buyer-connector.openapi.yaml 75 140
print_range docs/deployment/clearfolio-buyer-connector.openapi.yaml 250 390
printf '\n===== Administrative mappings and legacy permission/header references =====\n'
rg -n -C 3 \
'@(GetMapping|DeleteMapping|PostMapping)|admin:(read|write)|job:retry|X-Clearfolio-Operator-Id|retryDeadLetteredConversionJob' \
src/main/java docs/deployment/clearfolio-buyer-connector.openapi.yaml
printf '\n===== Audit logger call sites and logging statements =====\n'
rg -n -C 3 \
'administrativeAuditLogger|auditLogger|logger\.(info|warn|error|debug|trace)|recordDenied' \
src/main/java/com/clearfolio/viewer/controller/AdminController.java \
src/main/java/com/clearfolio/viewer/audit/AdministrativeAuditLogger.javaLength of output: 2090 🏁 Script executed: #!/bin/bash
set -euo pipefail
print_range() {
local path="$1" start="$2" end="$3"
printf '\n===== %s, lines %s-%s =====\n' "$path" "$start" "$end"
sed -n "${start},${end}p" "$path"
}
print_range src/main/java/com/clearfolio/viewer/auth/TenantAccessService.java 65 190
print_range src/main/java/com/clearfolio/viewer/controller/AdminController.java 45 285
print_range src/main/java/com/clearfolio/viewer/audit/AdministrativeAuditLogger.java 1 230
print_range src/main/java/com/clearfolio/viewer/repository/ConversionJobRepository.java 1 175
print_range src/main/java/com/clearfolio/viewer/repository/ConversionJobStateStore.java 1 135
print_range src/main/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepository.java 1 385
print_range src/main/java/com/clearfolio/viewer/service/DefaultDocumentConversionService.java 210 335
print_range docs/deployment/clearfolio-buyer-connector.openapi.yaml 75 140
print_range docs/deployment/clearfolio-buyer-connector.openapi.yaml 250 390
printf '\n===== Administrative mappings and legacy permission/header references =====\n'
rg -n -C 3 \
'@(GetMapping|DeleteMapping|PostMapping)|admin:(read|write)|job:retry|X-Clearfolio-Operator-Id|retryDeadLetteredConversionJob' \
src/main/java docs/deployment/clearfolio-buyer-connector.openapi.yaml
printf '\n===== Audit logger call sites and logging statements =====\n'
rg -n -C 3 \
'administrativeAuditLogger|auditLogger|logger\.(info|warn|error|debug|trace)|recordDenied' \
src/main/java/com/clearfolio/viewer/controller/AdminController.java \
src/main/java/com/clearfolio/viewer/audit/AdministrativeAuditLogger.javaLength of output: 82816 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '===== Worker enqueue and job lookup implementations ====='
rg -n -C 5 \
'\benqueue\s*\(|\bclaimForProcessing\s*\(|\bfindById\s*\(' \
src/main/java
printf '%s\n' '===== Retry, replacement, and stale-observation test coverage ====='
rg -n -i -C 6 \
'retry.*(replacement|concurrent|race|stale)|replacement.*retry|same.?UUID|sharedJobId|computeIfPresent|enqueue' \
src/test/java/com/clearfolio/viewer
printf '%s\n' '===== Full tenant retry and concurrency test files ====='
for path in \
src/test/java/com/clearfolio/viewer/service/TenantScopedRetryContractTest.java \
src/test/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepositoryConcurrencyTest.java \
src/test/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepositoryTenantScopeTest.java
do
printf '\n--- %s ---\n' "$path"
cat "$path"
doneLength of output: 170541
[P1] Serialize tenant retry with same-UUID replacement A concurrent sequence can therefore occur:
This breaks the tenant-bound retry invariant. It can also process a replacement that the retry caller did not authorize. Use the same critical section for the tenant-scoped retry transition and same-UUID replacement. Add a deterministic test that forces replacement after the retry transition but before enqueue or worker lookup. Affected code: I verified the stated parent relationship and inspected the signed-claim, least-privilege, fail-closed adapter-default, list, delete, audit, secret-source, and index boundaries. CI, Security Scan, and SAST remain absent-required. I did not treat them as passing. You are interacting with an AI system. |
|
@coderabbitai review @opencode-agent @cwl-noema-review Independently inspect exact current head Two review-discovered defects were fixed test-first and must be verified, not assumed:
Run |
🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
head='eea9c4c4442742d314bf532736f067e905a1e1f3'
parent='26563218ae42eaa876c784fcf56b27f8cb810080'
echo '== Exact commit relationship =='
git show -s --format='HEAD %H%nParents %P%nSubject %s' "$head"
printf 'merge-base: '; git merge-base "$head" "$parent"
printf 'ahead/behind: '; git rev-list --left-right --count "$parent...$head"
echo '== Parent-relative changed paths =='
git diff --name-status "$parent" "$head"
echo '== AGENTS.md parent-relative diff =='
git diff --unified=80 "$parent" "$head" -- AGENTS.md
echo '== Audit-related changed paths =='
git diff --name-only "$parent" "$head" | rg -i '(audit|admin|security|decision|pseudonym|test)' || true
echo '== Audit source/test structural outlines =='
fd -t f -i 'AuditPseudonymizer|AdministrativeAuditLogger' src | while IFS= read -r f; do
echo "--- $f ---"
ast-grep outline "$f" --items all --view compact || true
done
echo '== Job fingerprint, domains, raw jobId logging, and captured-log assertions =='
rg -n -i -C 4 \
'jobFingerprint|conversion[- ]job|jobId=|jobId\b|HMAC|domain|unavailable|absent|captur|appender' \
src/main/java src/test/java docs AGENTS.md 2>/dev/null || true
echo '== Security decision and current CWL/config-tree terms =='
rg -n -i -C 3 \
'administrative|audit|pseudonym|config[- ]tree|CWL|Netty|JaCoCo|javadoc|exact.head|zero.skip|verify' \
AGENTS.md docs src/main/resources src/test/java 2>/dev/null || true
echo '== Recent exact-head test and production diffs =='
git show --stat --oneline --decorate "$head"
git diff --unified=40 "${head}^..${head}" -- \
':(glob)**/*AuditPseudonymizer*.java' \
':(glob)**/*AdministrativeAuditLogger*.java' \
':(glob)**/*Audit*.java' \
':(glob)**/*security*' \
':(glob)**/*Security*' \
':(glob)**/AGENTS.md' || trueLength of output: 202329 🏁 Script executed: #!/bin/bash
set -euo pipefail
head='eea9c4c4442742d314bf532736f067e905a1e1f3'
parent='26563218ae42eaa876c784fcf56b27f8cb810080'
echo '== Relationship and changed-file count =='
printf 'merge-base='; git merge-base "$head" "$parent"
printf 'ahead_behind='; git rev-list --left-right --count "$parent...$head"
git diff --name-only "$parent" "$head" | tee /tmp/pr268-changed-files.txt
printf 'changed_file_count='; wc -l < /tmp/pr268-changed-files.txt
echo '== AGENTS.md diff and parent-equivalence outside config-tree terms =='
git diff --unified=12 "$parent" "$head" -- AGENTS.md
echo '-- parent and head AGENTS.md SHA-256 --'
git show "$parent:AGENTS.md" | sha256sum
git show "$head:AGENTS.md" | sha256sum
echo '-- changed AGENTS.md line numbers at head --'
git diff -U0 "$parent" "$head" -- AGENTS.md | rg '^@@|^[+-][^+-]' || true
echo '== Locate administrative audit implementation and decision =='
fd -t f -a . src/main/java src/test/java docs/security | rg \
'(AdministrativeAuditLogger|AuditPseudonymizer|administrative-authorization)' | sort
echo '== AdministrativeAuditLogger source and test =='
for f in \
src/main/java/com/clearfolio/viewer/audit/AdministrativeAuditLogger.java \
src/test/java/com/clearfolio/viewer/audit/AdministrativeAuditLoggerTest.java \
docs/security/2026-08-05-administrative-authorization.md
do
if [ -f "$f" ]; then
echo "--- $f ---"
nl -ba "$f"
fi
done
echo '== All AdministrativeAuditLogger call sites with context =='
rg -n -C 6 '\b(record|recordHeaders|jobFingerprint|actorFingerprint|tenantFingerprint)\s*\(' \
src/main/java/com/clearfolio/viewer \
-g '*.java'
echo '== Administrative-audit raw identifier fields or logs =='
rg -n -i -C 4 \
'(jobId=|jobId\b|conversion.?job|logger\.(info|warn|error|debug|trace)|log\.(info|warn|error|debug|trace))' \
src/main/java/com/clearfolio/viewer/controller/AdminController.java \
src/main/java/com/clearfolio/viewer/audit \
src/test/java/com/clearfolio/viewer/audit 2>/dev/null || true
echo '== Parent-relative audit/doc/test diffs =='
git diff --unified=20 "$parent" "$head" -- \
src/main/java/com/clearfolio/viewer/audit \
src/test/java/com/clearfolio/viewer/audit \
docs/security/2026-08-05-administrative-authorization.mdLength of output: 2709 🏁 Script executed: #!/bin/bash
set -euo pipefail
head='eea9c4c4442742d314bf532736f067e905a1e1f3'
parent='26563218ae42eaa876c784fcf56b27f8cb810080'
echo '== Changed-file count and paths =='
changed_files="$(git diff --name-only "$parent" "$head")"
printf '%s\n' "$changed_files"
printf 'changed_file_count='
printf '%s\n' "$changed_files" | awk 'NF { count += 1 } END { print count }'
echo '== AGENTS.md parent-relative diff =='
git diff --unified=16 "$parent" "$head" -- AGENTS.md
echo '== Relevant source and documentation files =='
fd -t f -a . src/main/java src/test/java docs/security | rg \
'(AdministrativeAuditLogger|AuditPseudonymizer|administrative-authorization)' | sort
for f in \
src/main/java/com/clearfolio/viewer/audit/AdministrativeAuditLogger.java \
src/test/java/com/clearfolio/viewer/audit/AdministrativeAuditLoggerTest.java \
docs/security/2026-08-05-administrative-authorization.md
do
if [ -f "$f" ]; then
echo "--- $f ---"
nl -ba "$f"
fi
done
echo '== Administrative logger call sites =='
rg -n -C 6 \
'administrativeAuditLogger\.(record|recordHeaders)|\b(record|recordHeaders)\s*\(' \
src/main/java/com/clearfolio/viewer \
-g '*.java'
echo '== Administrative audit raw-ID and logging references =='
rg -n -i -C 4 \
'(jobId=|jobId\b|conversion.?job|logger\.(info|warn|error|debug|trace)|log\.(info|warn|error|debug|trace))' \
src/main/java/com/clearfolio/viewer/controller/AdminController.java \
src/main/java/com/clearfolio/viewer/audit \
src/test/java/com/clearfolio/viewer/audit 2>/dev/null || true
echo '== Parent-relative audit, test, and decision diff =='
git diff --unified=24 "$parent" "$head" -- \
src/main/java/com/clearfolio/viewer/audit \
src/test/java/com/clearfolio/viewer/audit \
docs/security/2026-08-05-administrative-authorization.mdLength of output: 8601 🏁 Script executed: #!/bin/bash
set -euo pipefail
show_file() {
file="$1"
if [ -f "$file" ]; then
echo "--- $file ---"
sed -n '1,340p' "$file"
else
echo "--- missing: $file ---"
fi
}
show_file src/main/java/com/clearfolio/viewer/audit/AdministrativeAuditLogger.java
show_file src/test/java/com/clearfolio/viewer/audit/AdministrativeAuditLoggerTest.java
show_file src/main/java/com/clearfolio/viewer/security/AuditPseudonymizer.java
show_file src/test/java/com/clearfolio/viewer/security/AuditPseudonymizerTest.java
show_file docs/security/2026-08-05-administrative-authorization.md
echo '== AdministrativeAuditLogger construction and invocation sites =='
rg -n -C 8 \
'(new AdministrativeAuditLogger|AdministrativeAuditLogger|administrativeAuditLogger\.(record|recordHeaders))' \
src/main/java/com/clearfolio/viewer \
-g '*.java'
echo '== Every direct logger call in the administrative controller and audit package =='
rg -n -C 4 \
'(logger|log)\.(info|warn|error|debug|trace)\s*\(' \
src/main/java/com/clearfolio/viewer/controller/AdminController.java \
src/main/java/com/clearfolio/viewer/audit \
-g '*.java' || true
echo '== Exact job field names in audit implementation and captured-log tests =='
rg -n -C 5 \
'(jobFingerprint|jobId=|jobId\b|raw-job|raw.*UUID|UUID)' \
src/main/java/com/clearfolio/viewer/audit \
src/test/java/com/clearfolio/viewer/audit \
docs/security/2026-08-05-administrative-authorization.md \
-g '*.java' -g '*.md'
echo '== Parent-relative final audit/privacy commits =='
git log --format='%H %s' --ancestry-path \
26563218ae42eaa876c784fcf56b27f8cb810080..eea9c4c4442742d314bf532736f067e905a1e1f3
git show --format=fuller --stat 0e57c13401df51967c644980b4bb8d0d5db82cb9 \
2e6622ebe93c7f03bd019fe308aa346cecf8a908 \
4d453dfdbf76cd3cde2eaafbee875aee92eaa773 \
eea9c4c4442742d314bf532736f067e905a1e1f3Length of output: 80286
The merge base is the requested parent. The branch is 7 commits ahead and 0 commits behind. The parent-relative diff contains 31 files. I verified the two requested corrections:
I found one remaining actionable issue from the prior exact-head review. [P1] Serialize tenant retry with same-UUID replacement The commits after Use one shared critical section for same-UUID save and tenant-scoped retry. Add a deterministic test that replaces the UUID after the owned retry transition and before worker lookup. I could not run
|
|
@opencode-agent Fix the newly confirmed exact-head P1 retry/replacement race on CodeRabbit independently established this concrete sequence:
Required bounded correction:
Do not dismiss the finding merely because #263 will later add a durable outbox; this PR must not ship a tenant-crossing retry path. |
|
@coderabbitai review @opencode-agent @cwl-noema-review Review exact current head Verify signed-claim fail-closed construction, Run or inspect focused tests plus |
|
@opencode-agent Correct the authoritative evidence at exact current head The process-local Required bounded correction:
|
8713d20 to
73d1f77
Compare
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
head='73d1f77c67e417c51aa7548b7a43d4aea6ad4463'
parent='26563218ae42eaa876c784fcf56b27f8cb810080'
echo '== Exact relationship =='
git show -s --format='HEAD %H%nParents %P%nSubject %s' "$head"
printf 'merge_base='; git merge-base "$head" "$parent"
printf 'ahead_behind='; git rev-list --left-right --count "$parent...$head"
echo '== Parent-relative paths =='
git diff --name-status "$parent" "$head"
printf 'changed_file_count='
git diff --name-only "$parent" "$head" | awk 'NF { n++ } END { print n+0 }'
echo '== Prohibited cleanup/scheduling/workflow paths and annotations =='
git diff --name-only "$parent" "$head" | rg -i \
'(ArtifactCleanupQueue|ClearfolioViewerApplication|\.github/workflows|workflow|scheduler|scheduling)' || true
rg -n -C2 '`@EnableScheduling`|ArtifactCleanupQueue|retryPending' \
src/main/java src/test/java 2>/dev/null || true
echo '== Primary implementation outlines =='
for f in \
src/main/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepository.java \
src/main/java/com/clearfolio/viewer/repository/ConversionJobRepository.java \
src/main/java/com/clearfolio/viewer/repository/ConversionJobStateStore.java \
src/main/java/com/clearfolio/viewer/service/DefaultDocumentConversionService.java \
src/main/java/com/clearfolio/viewer/service/DefaultConversionWorker.java \
src/main/java/com/clearfolio/viewer/auth/TenantAccessService.java \
src/main/java/com/clearfolio/viewer/controller/AdminController.java \
src/main/java/com/clearfolio/viewer/audit/AdministrativeAuditLogger.java \
src/main/java/com/clearfolio/viewer/security/AuditPseudonymizer.java
do
echo "--- $f ---"
ast-grep outline "$f" --items all --view compact 2>/dev/null || true
done
echo '== UUID reservation, retry, dispatch, tenant/default paths =='
rg -n -C5 \
'reserved|reservation|tombstone|generation|existing == job|jobs\.put|putIfAbsent|findOrStoreByContentHash|retryDeadLetteredForTenant|deleteByTenantAndId|jobIndexLock|enqueue\s*\(|claimForProcessing|findById\s*\(|findAllByTenantId|findByTenantAnd(Id|ContentHash)' \
src/main/java/com/clearfolio/viewer \
-g '*.java'
echo '== Deterministic ownership/concurrency tests =='
rg -n -i -C5 \
'retry.*save|save.*retry|same.?UUID|tombston|reservation|replacement|collision|interleav|latch|enqueue|lifecycle' \
src/test/java/com/clearfolio/viewer \
-g '*.java'
echo '== Audit, claims, permissions, config-tree, and raw logging terms =='
rg -n -i -C3 \
'requireSigned|admin:(read|write)|forAdministrative(Job|Actor|Tenant)|jobFingerprint|jobId=|CLEARFOLIO_SECRET_CONFIG_DIR|config.tree|X-Clearfolio|logger\.(info|warn|error|debug|trace)' \
src/main/java src/main/resources src/test/java docs AGENTS.md \
-g '*.java' -g '*.yml' -g '*.yaml' -g '*.md'Length of output: 203318 🏁 Script executed: #!/bin/bash
set -euo pipefail
head='73d1f77c67e417c51aa7548b7a43d4aea6ad4463'
parent='26563218ae42eaa876c784fcf56b27f8cb810080'
show() {
local file="$1" start="$2" end="$3"
echo "===== ${file} lines ${start}-${end} ====="
nl -ba "$file" | sed -n "${start},${end}p"
}
show src/main/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepository.java 1 390
show src/main/java/com/clearfolio/viewer/repository/ConversionJobRepository.java 1 230
show src/main/java/com/clearfolio/viewer/repository/ConversionJobStateStore.java 1 180
show src/main/java/com/clearfolio/viewer/service/DefaultDocumentConversionService.java 220 315
show src/main/java/com/clearfolio/viewer/service/DefaultConversionWorker.java 160 230
show src/main/java/com/clearfolio/viewer/controller/AdminController.java 45 290
show docs/security/2026-08-05-administrative-authorization.md 1 180
show docs/deployment/2026-07-02-buyer-deployment-integration-playbook.md 1 330
show AGENTS.md 75 155
show CHANGELOG.md 1 150
echo '== All cleanup-queue, cleanup retry, scheduler, and durable-cleanup assertions =='
rg -n -i -C3 \
'ArtifactCleanupQueue|process-local.*(queue|retry)|cleanup.*(queue|retry|cadence|metric|evidence)|pending.*cleanup|`@EnableScheduling`|durable cleanup' \
AGENTS.md CHANGELOG.md docs src/main/java src/test/java \
-g '*.md' -g '*.java' -g '*.yml' -g '*.yaml' || true
echo '== Parent-relative diffs for source, contracts, tests, and documentation =='
git diff --unified=18 "$parent" "$head" -- \
src/main/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepository.java \
src/main/java/com/clearfolio/viewer/repository/ConversionJobRepository.java \
src/main/java/com/clearfolio/viewer/repository/ConversionJobStateStore.java \
src/main/java/com/clearfolio/viewer/service/DefaultDocumentConversionService.java \
src/main/java/com/clearfolio/viewer/service/DefaultConversionWorker.java \
src/test/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepositoryConcurrencyTest.java \
src/test/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepositoryTenantScopeTest.java \
src/test/java/com/clearfolio/viewer/service/TenantScopedRetryContractTest.java \
AGENTS.md CHANGELOG.md \
docs/deployment/2026-07-02-buyer-deployment-integration-playbook.md \
docs/security/2026-08-05-administrative-authorization.md
echo '== Administrative mappings, permissions, and service calls =='
rg -n -C4 \
'@(GetMapping|DeleteMapping|PostMapping)|TenantPermissions\.ADMIN_(READ|WRITE)|getJobsForTenant|deleteJob\(|retryDeadLettered\(' \
src/main/java/com/clearfolio/viewer/controller/AdminController.java \
src/main/java/com/clearfolio/viewer/service/DocumentConversionService.java \
src/main/java/com/clearfolio/viewer/service/DefaultDocumentConversionService.javaLength of output: 3264 🏁 Script executed: #!/bin/bash
set -euo pipefail
head='73d1f77c67e417c51aa7548b7a43d4aea6ad4463'
parent='26563218ae42eaa876c784fcf56b27f8cb810080'
show() {
local file="$1" start="$2" end="$3"
echo "===== ${file} lines ${start}-${end} ====="
awk -v start="$start" -v end="$end" \
'NR >= start && NR <= end { printf "%6d %s\n", NR, $0 }' "$file"
}
show src/main/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepository.java 1 390
show src/main/java/com/clearfolio/viewer/repository/ConversionJobRepository.java 1 230
show src/main/java/com/clearfolio/viewer/repository/ConversionJobStateStore.java 1 180
show src/main/java/com/clearfolio/viewer/service/DefaultDocumentConversionService.java 220 315
show src/main/java/com/clearfolio/viewer/service/DefaultConversionWorker.java 160 230
show src/main/java/com/clearfolio/viewer/controller/AdminController.java 45 290
show docs/security/2026-08-05-administrative-authorization.md 1 180
show docs/deployment/2026-07-02-buyer-deployment-integration-playbook.md 1 330
show AGENTS.md 75 155
show CHANGELOG.md 1 150
echo '== All cleanup-queue, cleanup retry, scheduler, and durable-cleanup assertions =='
rg -n -i -C3 \
'ArtifactCleanupQueue|process-local.*(queue|retry)|cleanup.*(queue|retry|cadence|metric|evidence)|pending.*cleanup|`@EnableScheduling`|durable cleanup' \
AGENTS.md CHANGELOG.md docs src/main/java src/test/java \
-g '*.md' -g '*.java' -g '*.yml' -g '*.yaml' || true
echo '== Parent-relative diffs for source, contracts, tests, and documentation =='
git diff --unified=18 "$parent" "$head" -- \
src/main/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepository.java \
src/main/java/com/clearfolio/viewer/repository/ConversionJobRepository.java \
src/main/java/com/clearfolio/viewer/repository/ConversionJobStateStore.java \
src/main/java/com/clearfolio/viewer/service/DefaultDocumentConversionService.java \
src/main/java/com/clearfolio/viewer/service/DefaultConversionWorker.java \
src/test/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepositoryConcurrencyTest.java \
src/test/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepositoryTenantScopeTest.java \
src/test/java/com/clearfolio/viewer/service/TenantScopedRetryContractTest.java \
AGENTS.md CHANGELOG.md \
docs/deployment/2026-07-02-buyer-deployment-integration-playbook.md \
docs/security/2026-08-05-administrative-authorization.md
echo '== Administrative mappings, permissions, and service calls =='
rg -n -C4 \
'@(GetMapping|DeleteMapping|PostMapping)|TenantPermissions\.ADMIN_(READ|WRITE)|getJobsForTenant|deleteJob\(|retryDeadLettered\(' \
src/main/java/com/clearfolio/viewer/controller/AdminController.java \
src/main/java/com/clearfolio/viewer/service/DocumentConversionService.java \
src/main/java/com/clearfolio/viewer/service/DefaultDocumentConversionService.javaLength of output: 234298
The requested parent is the merge base. The parent-relative scope contains 32 files. I found one actionable issue. [P1] Remove claims for the removed cleanup subsystem The reviewed source has no State the current behavior accurately:
I verified these static boundaries:
I could not run You are interacting with an AI system. |
|
@coderabbitai review @opencode-agent @cwl-noema-review Independently review exact current head Verify the 32-file administrative authorization slice only: signed-claim fail-closed construction; Confirm that the removed process-local cleanup queue, global scheduling enablement, cleanup configuration, temporary workflows, global lookup fallback, raw tenant/job/token logging, dependency drift, release, and unrelated automation are absent. The documentation must truthfully identify artifact deletion as current best effort and leave restart-safe receipts/outbox/cleanup recovery to issue #263. Same-head fuzz run |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
head='da03f567107ec0f6244bcc46720fb7af8bc2b2da'
parent='26563218ae42eaa876c784fcf56b27f8cb810080'
printf '%s\n' '== Exact relationship =='
git show -s --format='HEAD %H%nParents %P%nSubject %s' "$head"
printf 'merge_base='; git merge-base "$head" "$parent"
printf 'ahead_behind='; git rev-list --left-right --count "$parent...$head"
printf '%s\n' '== Parent-relative changed paths =='
git diff --name-status "$parent" "$head"
printf 'changed_file_count='
git diff --name-only "$parent" "$head" | awk 'NF { count++ } END { print count+0 }'
printf '%s\n' '== Prohibited scope paths =='
git diff --name-only "$parent" "$head" | rg -i \
'(ArtifactCleanupQueue|ClearfolioViewerApplication|\.github/workflows|workflow|scheduler|scheduling|pom\.xml|build\.gradle|package\.json)' || true
printf '%s\n' '== Structural outline of changed Java files =='
git diff --name-only "$parent" "$head" | while IFS= read -r path; do
case "$path" in
*.java)
printf '\n--- %s ---\n' "$path"
ast-grep outline "$path" --items all --view compact 2>/dev/null || true
;;
esac
doneLength of output: 6274 🏁 Script executed: #!/bin/bash
set -euo pipefail
show() {
local file="$1"
printf '\n===== %s =====\n' "$file"
nl -ba "$file"
}
for file in \
src/main/java/com/clearfolio/viewer/auth/TenantAccessService.java \
src/main/java/com/clearfolio/viewer/auth/TenantPermissions.java \
src/main/java/com/clearfolio/viewer/controller/AdminController.java \
src/main/java/com/clearfolio/viewer/repository/ConversionJobRepository.java \
src/main/java/com/clearfolio/viewer/repository/ConversionJobStateStore.java \
src/main/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepository.java \
src/main/java/com/clearfolio/viewer/service/DocumentConversionService.java \
src/main/java/com/clearfolio/viewer/service/DefaultDocumentConversionService.java \
src/main/java/com/clearfolio/viewer/service/DefaultConversionWorker.java \
src/main/java/com/clearfolio/viewer/audit/AdministrativeAuditLogger.java \
src/main/java/com/clearfolio/viewer/security/AuditPseudonymizer.java \
src/test/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepositoryConcurrencyTest.java \
src/test/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepositoryTenantScopeTest.java \
src/test/java/com/clearfolio/viewer/service/TenantScopedRetryContractTest.java \
src/test/java/com/clearfolio/viewer/service/TenantScopedAtomicMutationBoundaryTest.java \
src/test/java/com/clearfolio/viewer/audit/AdministrativeAuditLoggerTest.java \
docs/security/2026-08-05-administrative-authorization.md \
docs/deployment/2026-07-02-buyer-deployment-integration-playbook.md \
src/main/resources/application.yml \
src/main/resources/application-buyer-demo.yml
do
show "$file"
done
printf '\n===== Targeted prohibited implementation and unsafe logging scan =====\n'
rg -n -i -C 3 \
'ArtifactCleanupQueue|EnableScheduling|retryPending|findAll\s*\(|findById\s*\(|jobId=|logger\.(info|warn|error|debug|trace)|X-Clearfolio|CLEARFOLIO_TENANT_CLAIMS_HMAC_SECRET|CLEARFOLIO_SECRET_CONFIG_DIR' \
src/main/java src/main/resources src/test/java docs AGENTS.md CHANGELOG.md \
-g '*.java' -g '*.yml' -g '*.yaml' -g '*.md' || trueLength of output: 2552 🏁 Script executed: #!/bin/bash
set -euo pipefail
show() {
local file="$1"
printf '\n===== %s =====\n' "$file"
awk '{ printf "%6d %s\n", NR, $0 }' "$file"
}
for file in \
src/main/java/com/clearfolio/viewer/auth/TenantAccessService.java \
src/main/java/com/clearfolio/viewer/auth/TenantPermissions.java \
src/main/java/com/clearfolio/viewer/controller/AdminController.java \
src/main/java/com/clearfolio/viewer/repository/ConversionJobRepository.java \
src/main/java/com/clearfolio/viewer/repository/ConversionJobStateStore.java \
src/main/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepository.java \
src/main/java/com/clearfolio/viewer/service/DocumentConversionService.java \
src/main/java/com/clearfolio/viewer/service/DefaultDocumentConversionService.java \
src/main/java/com/clearfolio/viewer/service/DefaultConversionWorker.java \
src/main/java/com/clearfolio/viewer/audit/AdministrativeAuditLogger.java \
src/main/java/com/clearfolio/viewer/security/AuditPseudonymizer.java \
src/test/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepositoryConcurrencyTest.java \
src/test/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepositoryTenantScopeTest.java \
src/test/java/com/clearfolio/viewer/service/TenantScopedRetryContractTest.java \
src/test/java/com/clearfolio/viewer/service/TenantScopedAtomicMutationBoundaryTest.java \
src/test/java/com/clearfolio/viewer/audit/AdministrativeAuditLoggerTest.java \
docs/security/2026-08-05-administrative-authorization.md \
docs/deployment/2026-07-02-buyer-deployment-integration-playbook.md \
src/main/resources/application.yml \
src/main/resources/application-buyer-demo.yml
do
show "$file"
done
printf '\n===== Targeted prohibited implementation and unsafe logging scan =====\n'
rg -n -i -C 3 \
'ArtifactCleanupQueue|EnableScheduling|retryPending|findAll\s*\(|findById\s*\(|jobId=|logger\.(info|warn|error|debug|trace)|X-Clearfolio|CLEARFOLIO_TENANT_CLAIMS_HMAC_SECRET|CLEARFOLIO_SECRET_CONFIG_DIR' \
src/main/java src/main/resources src/test/java docs AGENTS.md CHANGELOG.md \
-g '*.java' -g '*.yml' -g '*.yaml' -g '*.md' || trueLength of output: 196463 🏁 Script executed: #!/bin/bash
set -euo pipefail
range() {
local file="$1" start="$2" end="$3"
printf '\n===== %s, lines %s-%s =====\n' "$file" "$start" "$end"
awk -v start="$start" -v end="$end" \
'NR >= start && NR <= end { printf "%6d %s\n", NR, $0 }' "$file"
}
range src/main/java/com/clearfolio/viewer/auth/TenantAccessService.java 1 220
range src/main/java/com/clearfolio/viewer/controller/AdminController.java 1 340
range src/main/java/com/clearfolio/viewer/repository/ConversionJobRepository.java 1 240
range src/main/java/com/clearfolio/viewer/repository/ConversionJobStateStore.java 1 190
range src/main/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepository.java 1 390
range src/main/java/com/clearfolio/viewer/service/DefaultDocumentConversionService.java 210 355
range src/main/java/com/clearfolio/viewer/service/DefaultConversionWorker.java 175 230
range src/main/java/com/clearfolio/viewer/audit/AdministrativeAuditLogger.java 1 230
range src/main/java/com/clearfolio/viewer/security/AuditPseudonymizer.java 1 260
range src/test/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepositoryConcurrencyTest.java 1 330
range src/test/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepositoryTenantScopeTest.java 55 310
range src/test/java/com/clearfolio/viewer/controller/AdminControllerTest.java 1 430
range src/test/java/com/clearfolio/viewer/auth/TenantAccessServiceStrictClaimsTest.java 1 180
range src/test/java/com/clearfolio/viewer/config/BuyerDemoSecretConfigurationTest.java 1 120
printf '\n===== Parent-relative implementation diff =====\n'
git diff --unified=16 \
26563218ae42eaa876c784fcf56b27f8cb810080 \
da03f567107ec0f6244bcc46720fb7af8bc2b2da -- \
src/main/java/com/clearfolio/viewer/auth/TenantAccessService.java \
src/main/java/com/clearfolio/viewer/controller/AdminController.java \
src/main/java/com/clearfolio/viewer/repository/ConversionJobRepository.java \
src/main/java/com/clearfolio/viewer/repository/ConversionJobStateStore.java \
src/main/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepository.java \
src/main/java/com/clearfolio/viewer/service/DefaultDocumentConversionService.java \
src/main/java/com/clearfolio/viewer/service/DocumentConversionService.java \
src/main/java/com/clearfolio/viewer/audit/AdministrativeAuditLogger.java \
src/main/java/com/clearfolio/viewer/security/AuditPseudonymizer.javaLength of output: 197828
The merge base is the requested parent. The branch is 48 commits ahead and 0 commits behind. The parent-relative diff contains 32 files. I found two actionable issues.
I also verified these static boundaries:
I could not run I treated fuzz run You are interacting with an AI system. |
|
Exact-head review requested for The authoritative documentation now states the actual cleanup boundary: this slice has no cleanup queue, deletion receipt, outbox, retry cadence, cleanup metrics, or durable recovery evidence. Artifact removal remains best effort and can leave orphaned bytes; issue #263 owns the production-grade cleanup subsystem. The remaining Exact-head fuzz run |
|
@coderabbitai review @opencode-agent @cwl-noema-review Please independently inspect exact current head |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
head='da03f567107ec0f6244bcc46720fb7af8bc2b2da'
parent='26563218ae42eaa876c784fcf56b27f8cb810080'
echo '== Exact relationship =='
git show -s --format='HEAD %H%nParents %P%nSubject %s' "$head"
printf 'merge_base='; git merge-base "$head" "$parent"
printf 'ahead_behind='; git rev-list --left-right --count "$parent...$head"
echo '== Parent-relative changed paths =='
git diff --name-status "$parent" "$head"
printf 'changed_file_count='
git diff --name-only "$parent" "$head" | awk 'NF { count++ } END { print count+0 }'
echo '== Relevant source outlines =='
for file in \
src/main/java/com/clearfolio/viewer/service/DefaultDocumentConversionService.java \
src/main/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepository.java \
src/main/java/com/clearfolio/viewer/service/DefaultConversionWorker.java \
src/main/java/com/clearfolio/viewer/audit/AdministrativeAuditLogger.java \
src/main/java/com/clearfolio/viewer/controller/AdminController.java
do
echo "--- $file ---"
ast-grep outline "$file" --items all --view compact 2>/dev/null || true
done
echo '== Artifact deletion, UUID collision, retry dispatch, and worker lookup =='
rg -n -C 8 \
'deleteArtifact\s*\(|Failed to delete artifact|findOrStoreByContentHash\s*\(|storeNewCandidate\s*\(|reserved|reservation|existing == job|retryDeadLetteredForTenant\s*\(|enqueue\s*\(|findById\s*\(' \
src/main/java/com/clearfolio/viewer/service/DefaultDocumentConversionService.java \
src/main/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepository.java \
src/main/java/com/clearfolio/viewer/service/DefaultConversionWorker.java
echo '== Relevant test coverage =='
rg -n -i -C 6 \
'same.*tenant.*same.*hash|findOrStoreByContentHash|tombston|collision|retry.*save|save.*retry|artifact.*delete|raw.*UUID|jobId=' \
src/test/java/com/clearfolio/viewer \
-g '*.java'
echo '== Parent-relative diffs for inspected code and tests =='
git diff --unified=24 "$parent" "$head" -- \
src/main/java/com/clearfolio/viewer/service/DefaultDocumentConversionService.java \
src/main/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepository.java \
src/main/java/com/clearfolio/viewer/service/DefaultConversionWorker.java \
':(glob)src/test/java/**/*ConversionJobRepository*Test.java' \
':(glob)src/test/java/**/*TenantScopedRetry*Test.java'
echo '== Prohibited scope and cleanup assertions =='
git diff --name-only "$parent" "$head" | rg -i \
'(ArtifactCleanupQueue|ClearfolioViewerApplication|\.github/workflows|workflow|scheduler|scheduling|pom\.xml|build\.gradle|package\.json)' || true
rg -n -i -C 3 \
'ArtifactCleanupQueue|EnableScheduling|cleanup queue|retry cadence|cleanup metrics|durable cleanup' \
AGENTS.md CHANGELOG.md docs src/main/java src/test/java \
-g '*.md' -g '*.java' -g '*.yml' -g '*.yaml' || trueLength of output: 186236
The requested parent is the merge base. The branch is 48 commits ahead and 0 commits behind. The parent-relative diff contains 32 files. I found two actionable issues.
I also verified these exact-head static conditions:
I could not run Maven or Python commands in this sandbox. Test totals, failures, skips, JaCoCo coverage, and Javadoc warnings remain unverified. You are interacting with an AI system. |
|
@coderabbitai review @opencode-agent @cwl-noema-review Please independently inspect exact current head |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
head='e25e62224aa61583f0f8df39465aae7eaf59c9f3'
parent='26563218ae42eaa876c784fcf56b27f8cb810080'
prior='da03f567107ec0f6244bcc46720fb7af8bc2b2da'
echo '== Exact relationship =='
git show -s --format='HEAD %H%nParents %P%nSubject %s' "$head"
printf 'merge_base='; git merge-base "$head" "$parent"
printf 'ahead_behind='; git rev-list --left-right --count "$parent...$head"
echo '== Parent-relative changed paths =='
git diff --name-status "$parent" "$head"
printf 'changed_file_count='
git diff --name-only "$parent" "$head" | awk 'NF { n++ } END { print n+0 }'
echo '== Changes since the prior reviewed head =='
git log --oneline --ancestry-path "${prior}..${head}"
git diff --name-status "$prior" "$head"
git diff --unified=32 "$prior" "$head" -- \
src/main/java/com/clearfolio/viewer/service/DefaultDocumentConversionService.java \
src/main/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepository.java \
src/test/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepositoryTenantScopeTest.java \
src/test/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepositoryConcurrencyTest.java \
src/test/java/com/clearfolio/viewer/service/TenantScopedRetryContractTest.java \
src/test/java/com/clearfolio/viewer/service/TenantScopedAtomicMutationBoundaryTest.java \
docs/security/2026-08-05-administrative-authorization.md \
CHANGELOG.md
echo '== Changed Java file structure =='
git diff --name-only "$parent" "$head" | while IFS= read -r path; do
case "$path" in
*.java)
echo "--- $path ---"
ast-grep outline "$path" --items all --view compact 2>/dev/null || true
;;
esac
done
echo '== Inspect sensitive implementation paths =='
for file in \
src/main/java/com/clearfolio/viewer/service/DefaultDocumentConversionService.java \
src/main/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepository.java \
src/main/java/com/clearfolio/viewer/service/DefaultConversionWorker.java \
src/main/java/com/clearfolio/viewer/controller/AdminController.java \
src/main/java/com/clearfolio/viewer/auth/TenantAccessService.java \
src/main/java/com/clearfolio/viewer/audit/AdministrativeAuditLogger.java \
src/main/java/com/clearfolio/viewer/security/AuditPseudonymizer.java \
src/main/java/com/clearfolio/viewer/repository/ConversionJobRepository.java \
src/main/java/com/clearfolio/viewer/repository/ConversionJobStateStore.java \
src/main/java/com/clearfolio/viewer/service/DocumentConversionService.java
do
echo "--- $file ---"
nl -ba "$file"
done
echo '== Focused implementation and test search =='
rg -n -i -C 5 \
'deleteArtifact|Failed to delete artifact|logger\.(info|warn|error|debug|trace)|jobId=|jobFingerprint|findOrStoreByContentHash|storeNewCandidate|reserved|tombstone|existing == job|same.?tenant|same.?hash|collision|retryDeadLetteredForTenant|enqueue\s*\(|claimForProcessing|findById\s*\(|requireSigned|admin:(read|write)|forAdministrative(Job|Actor|Tenant)|CLEARFOLIO_SECRET_CONFIG_DIR|ArtifactCleanupQueue|EnableScheduling' \
src/main/java src/test/java src/main/resources docs AGENTS.md CHANGELOG.md \
-g '*.java' -g '*.yml' -g '*.yaml' -g '*.md' || true
echo '== Scope exclusions =='
git diff --name-only "$parent" "$head" | rg -i \
'(ArtifactCleanupQueue|ClearfolioViewerApplication|\.github/workflows|workflow|scheduler|scheduling|pom\.xml|build\.gradle|package\.json)' || trueLength of output: 14120 🏁 Script executed: #!/bin/bash
set -euo pipefail
head='e25e62224aa61583f0f8df39465aae7eaf59c9f3'
parent='26563218ae42eaa876c784fcf56b27f8cb810080'
prior='da03f567107ec0f6244bcc46720fb7af8bc2b2da'
numbered() {
file="$1"
echo "===== $file ====="
awk '{ printf "%6d %s\n", NR, $0 }' "$file"
}
echo '== Exact source and test material for prior findings =='
for file in \
src/main/java/com/clearfolio/viewer/service/DefaultDocumentConversionService.java \
src/main/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepository.java \
src/test/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepositoryTenantScopeTest.java \
src/test/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepositoryConcurrencyTest.java \
src/test/java/com/clearfolio/viewer/service/TenantScopedRetryContractTest.java \
src/test/java/com/clearfolio/viewer/service/TenantScopedAtomicMutationBoundaryTest.java
do
numbered "$file"
done
echo '== Exact diffs for prior findings =='
git diff --unified=60 "$prior" "$head" -- \
src/main/java/com/clearfolio/viewer/service/DefaultDocumentConversionService.java \
src/main/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepository.java \
src/test/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepositoryTenantScopeTest.java \
src/test/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepositoryConcurrencyTest.java
echo '== Authorization, audit, contract, config, and documentation boundaries =='
for file in \
src/main/java/com/clearfolio/viewer/controller/AdminController.java \
src/main/java/com/clearfolio/viewer/auth/TenantAccessService.java \
src/main/java/com/clearfolio/viewer/repository/ConversionJobRepository.java \
src/main/java/com/clearfolio/viewer/repository/ConversionJobStateStore.java \
src/main/java/com/clearfolio/viewer/service/DocumentConversionService.java \
src/main/java/com/clearfolio/viewer/audit/AdministrativeAuditLogger.java \
src/main/java/com/clearfolio/viewer/security/AuditPseudonymizer.java \
src/main/resources/application.yml \
src/main/resources/application-buyer-demo.yml \
docs/security/2026-08-05-administrative-authorization.md \
docs/deployment/2026-07-02-buyer-deployment-integration-playbook.md
do
numbered "$file"
done
echo '== Targeted calls, logs, validation order, and test assertions =='
rg -n -C 8 \
'deleteArtifact\s*\(|Failed to delete artifact|log\.(info|warn|error|debug|trace)\s*\(|findOrStoreByContentHash\s*\(|storeNewCandidate\s*\(|ensure.*(Reservation|Identifier)|reserved|tombston|existing == job|same.?tenant|same.?hash|distinct.*(job|object)|retryDeadLetteredForTenant\s*\(|enqueue\s*\(|claimForProcessing\s*\(|findById\s*\(|requireSigned\s*\(|ADMIN_(READ|WRITE)|jobFingerprint|forAdministrative(Job|Actor|Tenant)|CLEARFOLIO_SECRET_CONFIG_DIR|ArtifactCleanupQueue|EnableScheduling' \
src/main/java src/test/java src/main/resources docs AGENTS.md CHANGELOG.md \
-g '*.java' -g '*.yml' -g '*.yaml' -g '*.md' || true
echo '== Parent-relative diffs for all security-critical implementation =='
git diff --unified=24 "$parent" "$head" -- \
src/main/java/com/clearfolio/viewer/service/DefaultDocumentConversionService.java \
src/main/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepository.java \
src/main/java/com/clearfolio/viewer/controller/AdminController.java \
src/main/java/com/clearfolio/viewer/auth/TenantAccessService.java \
src/main/java/com/clearfolio/viewer/repository/ConversionJobRepository.java \
src/main/java/com/clearfolio/viewer/repository/ConversionJobStateStore.java \
src/main/java/com/clearfolio/viewer/service/DocumentConversionService.java \
src/main/java/com/clearfolio/viewer/audit/AdministrativeAuditLogger.java \
src/main/java/com/clearfolio/viewer/security/AuditPseudonymizer.java
echo '== Prohibited parent-relative paths =='
git diff --name-only "$parent" "$head" | rg -i \
'(ArtifactCleanupQueue|ClearfolioViewerApplication|\.github/workflows|workflow|scheduler|scheduling|pom\.xml|build\.gradle|package\.json)' || trueLength of output: 143916
The requested parent I found two actionable exact-head issues.
I verified these static conditions:
I could not run Maven or Python in this sandbox. Test totals, skips, coverage, and Javadoc warnings remain unverified. The exact-head fuzz run is queued. CI, Security Scan, and SAST are absent. I did not treat any of these checks as passing. You are interacting with an AI system. |
|
@opencode-agent Implement the two CodeRabbit findings on exact current branch head after RED commits Bounded production work only:
|
|
@coderabbitai review @opencode-agent @cwl-noema-review Please independently review exact current head Focus on the five commits after predecessor head Exact-head fuzz run |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
head='7f341e00ec6c0908b7b250167392fdbc743cac50'
parent='26563218ae42eaa876c784fcf56b27f8cb810080'
prior='e25e62224aa61583f0f8df39465aae7eaf59c9f3'
echo '== Exact relationship =='
git show -s --format='HEAD %H%nParents %P%nSubject %s' "$head"
printf 'merge_base='; git merge-base "$head" "$parent"
printf 'ahead_behind='; git rev-list --left-right --count "$parent...$head"
echo '== Commits since prior reviewed head =='
git log --format='%H %s' --ancestry-path "${prior}..${head}"
echo '== Parent-relative changed paths =='
git diff --name-status "$parent" "$head"
printf 'changed_file_count='
git diff --name-only "$parent" "$head" | awk 'NF { count++ } END { print count+0 }'
echo '== Changes since prior head =='
git diff --name-status "$prior" "$head"
git diff --unified=36 "$prior" "$head" -- \
src/main/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepository.java \
src/main/java/com/clearfolio/viewer/service/DefaultDocumentConversionService.java \
src/test/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepositoryTenantScopeTest.java \
src/test/java/com/clearfolio/viewer/service/TenantScopedAtomicMutationBoundaryTest.java
echo '== Target file outlines =='
for f in \
src/main/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepository.java \
src/main/java/com/clearfolio/viewer/service/DefaultDocumentConversionService.java \
src/test/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepositoryTenantScopeTest.java \
src/test/java/com/clearfolio/viewer/service/TenantScopedAtomicMutationBoundaryTest.java \
src/test/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepositoryConcurrencyTest.java
do
echo "--- $f ---"
ast-grep outline "$f" --items all --view compact 2>/dev/null || true
done
echo '== Candidate ownership, index lookup, retry dispatch, and log redaction =='
rg -n -C 8 \
'findOrStoreByContentHash\s*\(|storeNewCandidate\s*\(|reservation|reserved|tombston|existing == job|contentHash\s*\(|jobsByTenantAndContentHash|deleteArtifact\s*\(|Failed to delete artifact|log\.(info|warn|error|debug|trace)\s*\(|retryDeadLetteredForTenant\s*\(|enqueue\s*\(|claimForProcessing\s*\(|findById\s*\(' \
src/main/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepository.java \
src/main/java/com/clearfolio/viewer/service/DefaultDocumentConversionService.java \
src/main/java/com/clearfolio/viewer/service/DefaultConversionWorker.java \
src/test/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepositoryTenantScopeTest.java \
src/test/java/com/clearfolio/viewer/service/TenantScopedAtomicMutationBoundaryTest.java \
src/test/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepositoryConcurrencyTest.java
echo '== Authorization, audit domains, config-tree, and scope exclusions =='
rg -n -C 4 \
'requireSigned\s*\(|ADMIN_(READ|WRITE)|forAdministrative(Job|Actor|Tenant)|jobFingerprint|CLEARFOLIO_SECRET_CONFIG_DIR|findAllByTenantId|findByTenantAnd(Id|ContentHash)|deleteByTenantAndId|retryDeadLetteredForTenant' \
src/main/java src/main/resources \
-g '*.java' -g '*.yml' -g '*.yaml'
echo '== Prohibited paths and implementation markers =='
git diff --name-only "$parent" "$head" | rg -i \
'(ArtifactCleanupQueue|ClearfolioViewerApplication|\.github/workflows|workflow|scheduler|scheduling|pom\.xml|build\.gradle|package\.json)' || true
rg -n -i -C 2 \
'ArtifactCleanupQueue|EnableScheduling|cleanup queue|retry cadence|cleanup metrics' \
src/main/java src/test/java docs AGENTS.md CHANGELOG.md \
-g '*.java' -g '*.md' -g '*.yml' -g '*.yaml' || trueLength of output: 151278 🏁 Script executed: #!/bin/bash
set -euo pipefail
head='7f341e00ec6c0908b7b250167392fdbc743cac50'
prior='e25e62224aa61583f0f8df39465aae7eaf59c9f3'
show_file() {
local file="$1"
echo "===== $file ====="
nl -ba "$file"
}
show_file src/test/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepositoryIdentifierContractTest.java
show_file src/test/java/com/clearfolio/viewer/service/ArtifactDeletionPrivacyTest.java
echo '== New-test diffs =='
git diff --unified=80 "$prior" "$head" -- \
src/test/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepositoryIdentifierContractTest.java \
src/test/java/com/clearfolio/viewer/service/ArtifactDeletionPrivacyTest.java
echo '== Full find-or-store and identifier-reservation helpers =='
sed -n '45,125p' src/main/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepository.java | nl -ba -v45
sed -n '350,430p' src/main/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepository.java | nl -ba -v350
echo '== Full artifact-delete helper and all service log calls =='
sed -n '215,345p' src/main/java/com/clearfolio/viewer/service/DefaultDocumentConversionService.java | nl -ba -v215
rg -n -C 3 'log\.(trace|debug|info|warn|error)\s*\(' \
src/main/java/com/clearfolio/viewer/service/DefaultDocumentConversionService.java
echo '== Retry/save deterministic regression and collision assertions =='
rg -n -i -C 8 \
'retry.*save|save.*retry|replacement|sharedJobId|reserved|tombston|findOrStore.*collision|content.?hash.*access|contentHash.*throw|lifecycle' \
src/test/java/com/clearfolio/viewer/repository \
-g '*.java'
echo '== New tests: static imports and test dependencies =='
rg -n -C 1 \
'^(import static|import )|`@Test`|assert(Throws|Equals|False|True|Same)|fail\(' \
src/test/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepositoryIdentifierContractTest.java \
src/test/java/com/clearfolio/viewer/service/ArtifactDeletionPrivacyTest.javaLength of output: 2407 🏁 Script executed: #!/bin/bash
set -euo pipefail
head='7f341e00ec6c0908b7b250167392fdbc743cac50'
prior='e25e62224aa61583f0f8df39465aae7eaf59c9f3'
show_file() {
local file="$1"
echo "===== $file ====="
awk '{ printf "%6d %s\n", NR, $0 }' "$file"
}
show_range() {
local file="$1" start="$2" end="$3"
echo "===== $file lines $start-$end ====="
awk -v start="$start" -v end="$end" \
'NR >= start && NR <= end { printf "%6d %s\n", NR, $0 }' "$file"
}
show_file src/test/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepositoryIdentifierContractTest.java
show_file src/test/java/com/clearfolio/viewer/service/ArtifactDeletionPrivacyTest.java
echo '== New-test diffs =='
git diff --unified=80 "$prior" "$head" -- \
src/test/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepositoryIdentifierContractTest.java \
src/test/java/com/clearfolio/viewer/service/ArtifactDeletionPrivacyTest.java
show_range src/main/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepository.java 45 125
show_range src/main/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepository.java 350 430
echo '== Artifact-delete helper and direct service log calls =='
show_range src/main/java/com/clearfolio/viewer/service/DefaultDocumentConversionService.java 215 345
rg -n -C 3 'log\.(trace|debug|info|warn|error)\s*\(' \
src/main/java/com/clearfolio/viewer/service/DefaultDocumentConversionService.java
echo '== Retry/save deterministic regression and collision assertions =='
rg -n -i -C 8 \
'retry.*save|save.*retry|replacement|sharedJobId|reserved|tombston|findOrStore.*collision|content.?hash.*access|contentHash.*throw|lifecycle' \
src/test/java/com/clearfolio/viewer/repository \
-g '*.java'
echo '== New-test imports and assertions =='
rg -n -C 1 \
'^(import static|import )|`@Test`|assert(Throws|Equals|False|True|Same)|fail\(' \
src/test/java/com/clearfolio/viewer/repository/InMemoryConversionJobRepositoryIdentifierContractTest.java \
src/test/java/com/clearfolio/viewer/service/ArtifactDeletionPrivacyTest.javaLength of output: 135107
I found no new actionable finding in the requested changes. The merge base is parent I verified the five commits after
I also verified the existing static boundaries:
I accept the stated successful exact-head fuzz run I could not run Maven or Python commands in this sandbox. Exact test totals, zero skips, JaCoCo coverage, and Javadoc warnings remain unverified. I did not infer independent human approval. You are interacting with an AI system. |
Security objective
Make every administrative conversion-job endpoint fail closed under signed tenant claims, least-privilege permissions, tenant-scoped persistence queries, atomic tenant-scoped mutations, immutable job identity, tenant-bound secondary indexes, and privacy-safe audit evidence.
This draft supersedes closed #266 and is stacked directly on authoritative parent #270 through base branch
fix/pii-logging-16240128950440010639. Administrative audit evidence reuses and preserves the parent’s dedicated keyed pseudonymization contract.Security boundary
admin:readfor tenant-scoped listing andadmin:writefor delete and retry;503before repository access when the signed-claim HMAC verifier is absent or shorter than 32 UTF-8 bytes;findAllByTenantIdbefore job objects cross the repository/service boundary;TenantContextinto delete and retry service mutations;deleteByTenantAndIdandretryDeadLetteredForTenantcontracts whose compatibility defaults fail closed without global lookup or legacy mutation;Test-first retry-race remediation
CodeRabbit identified a valid tenant-crossing retry race on predecessor head
fe2e53328a0b44c1c449d724314c6c4944eb572b: Tenant A could complete an authorized dead-letter transition, a distinct Tenant B object could replace the same UUID before enqueue, and the UUID-only worker lookup could then process Tenant B’s replacement.The current implementation closes that path by making job identifiers non-reusable. A deterministic latch-based regression pauses the accepted retry before enqueue, forces the cross-tenant replacement attempt, requires collision rejection, and proves the worker resolves only the original Tenant A object with no Tenant B lifecycle evidence. Additional tests cover exact-object save and find-or-store idempotence, collision rejection before candidate content-hash access, live and tombstoned UUID collision rejection, secondary-index ownership, delete/save interleavings, missing and cross-tenant concealment, and fail-closed adapter defaults.
Privacy-safe failure evidence
Artifact deletion remains best effort, but failure diagnostics no longer interpolate the raw conversion-job UUID or attach an exception whose message can contain a storage path or document identifier. A deterministic Log4j regression injects exception-controlled sensitive text and verifies that the emitted event contains only the fixed controlled message and no throwable.
This log hardening does not convert best-effort deletion into durable cleanup evidence.
Artifact-cleanup boundary
The current deletion path removes the tenant-owned repository record before a best-effort artifact-store deletion. An artifact-store failure is logged and does not restore the job, so orphaned bytes can remain. This PR does not implement a cleanup queue, deletion receipt, transactional outbox, retry worker, retry cadence, or aggregate cleanup evidence. Issue #263 owns the restart-safe cleanup subsystem and deterministic recovery evidence.
The remaining CodeRabbit thread on
DefaultDocumentConversionService.deleteArtifactis therefore valid and intentionally unresolved. Authoritative agent, security, and deployment documentation state this limitation rather than claiming a nonexistent cleanup subsystem.Exact current tree
Exact current head is
7f341e00ec6c0908b7b250167392fdbc743cac50.It is a clean descendant of parent #270 exact head
26563218ae42eaa876c784fcf56b27f8cb810080, 54 commits ahead and 0 behind, with a 34-file parent-relative diff. The five commits after stale body heade25e62224aa61583f0f8df39465aae7eaf59c9f3modify only the in-memory identifier contract, the artifact-deletion diagnostic, and their deterministic regression tests. The exact current tip isfix(security): redact artifact deletion failure logs.No cleanup-queue implementation, global scheduling enablement, temporary/write-scoped workflow, dependency change, release change, or unrelated automation is present.
Exact-head evidence
For exact current head
7f341e00ec6c0908b7b250167392fdbc743cac50:31071432102: completed successfully;mainbase and are not passing;d55490707c24a71ae26ef208e0c0f6618606275cand is stale for this head;mvn verify, coverage, Javadoc, or script result is represented as shareable exact-head acceptance evidence.Queued, pending, cancelled, skipped-required, absent-required, stale-head, predecessor-head, local-only, synthetic-only, or advisory-only evidence is not passing.
Merge order and gate
Keep this PR draft. Parent #270 must satisfy every exact-head protection, receive a counted independent approval, and integrate first. Then reconcile this bounded tree onto protected
mainand rerun exact-headmvn -B --no-transfer-progress verify, complete Surefire/Failsafe evidence, zero missed production lines and branches, warning-free public Javadocs, CI, Security Scan, SAST, every required fuzz job, CodeRabbit, Strix/OpenCode/Noema review, zero unresolved actionable threads, a counted independent write-authorized approval, and every repository protection.Do not manufacture checks by temporary retargeting, restore same-UUID replacement, add a global lookup or legacy mutation fallback, reintroduce a process-local cleanup queue, weaken tests, publish a release, resolve the valid cleanup thread prematurely, or bypass branch protection.